package lib.bone.admin.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lib.bone.admin.anno.WebLog;
import lib.bone.common.constant.ResponseCodeConst;
import lib.bone.common.exception.BusinessException;
import lib.bone.common.utils.JsonUtil;
import lib.bone.system.domain.entity.SysUser;
import lib.bone.system.module.log.SysLog;
import lib.bone.system.module.log.SysLogService;
import lib.bone.system.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Aspect
@Component
public class WebLogAspect {

    @Autowired
    SysUserService userService;

    @Autowired
    SysLogService logService;

    /**
     * 以自定义注解作为切入
     */
    @Pointcut("@annotation(lib.bone.admin.anno.WebLog)")
    public void WebLog(){}

    /**
     * 切面
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("WebLog()")
    public Object handleWebLog(ProceedingJoinPoint joinPoint) throws Throwable {
        return recordWebLog(joinPoint);
    }


    public Object recordWebLog(ProceedingJoinPoint joinPoint) throws Throwable {
        // 初始化日志类
        SysLog sysLog = new SysLog();
        // 获取注解
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        // 获取自定义注解信息
        WebLog webLog = method.getAnnotation(WebLog.class);
        // 获取匿名 允许状态 默认为不允许
        Integer allowMask = webLog.allowMask();
        if (allowMask.equals(1)){
            sysLog.setOperator("匿名用户");
        }else {
            // 获取用户信息
            Long userId = StpUtil.getLoginIdAsLong();
            // 设置操作人ID
            sysLog.setOperatorId(userId);
            Optional<SysUser> userOp = userService.getById(userId);
            if (!userOp.isPresent()){
                throw new BusinessException(ResponseCodeConst.UNAUTHORIZED,"该接口禁止未登录请求");
            }else {
                // 设置操作人姓名
                sysLog.setOperator(userOp.get().getNickName());
            }
        }

        // 获取模块信息
        String module = webLog.module();
        sysLog.setModule(module);
        // 获取操作信息
        String operate = webLog.operate();
        sysLog.setContent(operate);
        // 获取类与方法信息
        Object target = joinPoint.getTarget();
        String className = target.getClass().getName();
        String methodName = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes()).getName();
        sysLog.setClazz(className);
        sysLog.setMethod(methodName);
        // 获取请求IP
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String clientIP = ServletUtil.getClientIP(request);
        sysLog.setClientIp(clientIP);
        // 设置请求参数
        //获取入参
        Object[] objs = joinPoint.getArgs();
        String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); // 参数名
        Map<String, Object> paramMap = new HashMap<String, Object>();
        for (int i = 0; i < objs.length; i++) {
            paramMap.put(argNames[i], objs[i]);
        }
        sysLog.setParams(JSON.toJSONString(paramMap));
        // 设置开始时间
        long startTime = System.currentTimeMillis();
        sysLog.setStartTime(new Date());

        try {
            Object object = joinPoint.proceed();
            sysLog.setStatus(1);
            sysLog.setEndTime(new Date());
            sysLog.setTotalTime((int) (System.currentTimeMillis() - startTime));
            // 返回值
            if (null != object) {
                String returnData = JsonUtil.obj2String(object);
                sysLog.setReturnData(returnData);
            }
            return object;
        } catch (Throwable e) {
            sysLog.setStatus(0);
            sysLog.setEndTime(new Date());
            sysLog.setTotalTime((int) (System.currentTimeMillis() - startTime));
            sysLog.setContent(e.getMessage());
            throw e;
        } finally {

           logService.saveOne(sysLog);
        }
    }

}
